/*
 * Gestalt
 *
 * Copyright (C) 2009 Patrick Kochlik + Dennis Paul
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 * {@link http://www.gnu.org/licenses/lgpl.html}
 *
 */


package com.briansteen.sketches;

import java.io.DataInputStream;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import xx.codeflower.panoramio.PanoramioRequest;
import xx.codeflower.whois.WhoisRequest;

import cc.creativecomputing.io.CCIOUtil;

import com.briansteen.utils.GeoPosition;

import nanoxml.XMLElement;
import net.roarsoftware.lastfm.Event;
import net.roarsoftware.lastfm.Geo;
import net.roarsoftware.lastfm.PaginatedResult;
import gestalt.G;
import gestalt.render.AnimatorRenderer;
import gestalt.texture.Bitmaps;
import gestalt.util.CameraMover;
import data.Resource;
import gestalt.candidates.JoglLEDDisplay;
import gestalt.context.DisplayCapabilities;
import gestalt.render.plugin.ArcBall;
import mathematik.Vector3f;


public class GeoDataVisualization
        extends AnimatorRenderer {

    
    private float _myCounter;
    private float latitudeOffset = 52.5f;
    private float longitudeOffset = 13.4f;
    private float magnify = 500;
    
    // lastfm
    private String _lastfm_key = "b25b959554ed76058ac220b7b2e0a026"; //this is the key used in the last.fm API examples online.
    private ArrayList<GeoPosition> _lastfm_positions = new ArrayList<GeoPosition>();
    private JoglLEDDisplay _lastfm_mesh;
    
    // flickr
    private String _flickr_api_key = "db31e74674556a3bed55e758302c1a23";
	private ArrayList<GeoPosition> _flickr_positions = new ArrayList<GeoPosition>();
	private int _flickr_photosAmount = 800;
	private JoglLEDDisplay _flickr_mesh;
	
	// panoramio
	private PanoramioRequest r = new PanoramioRequest();
	private ArrayList<GeoPosition> _panoramio_positions = new ArrayList<GeoPosition>();
	private JoglLEDDisplay _panoramio_mesh;
	
	// twitter
	private JSONArray _twitterData;
	private ArrayList<GeoPosition> _twitter_positions = new ArrayList<GeoPosition>();
	private JoglLEDDisplay _twitter_mesh;
	
	// potsdam
	private ArrayList<GeoPosition> _home_positions = new ArrayList<GeoPosition>();
	private JoglLEDDisplay _home_mesh;
	
	
    
    public void setup() {
    	
    	/*
    	 * get data
    	 */
    	
    	// get geodata from lastfm
		PaginatedResult<Event> events = Geo.getEvents("Berlin", null, _lastfm_key);
		int pageAmount = events.getTotalPages();
		for(int i=0;i<pageAmount;i++) {
			PaginatedResult<Event> eventsPerPage = Geo.getEvents("Berlin", null, i, _lastfm_key);
			System.out.println("page " + i);
			for (Event event : eventsPerPage.getPageResults()) {
				System.out.println(event.getLatitude() + " " + event.getLongitude());
				_lastfm_positions.add(new GeoPosition(event.getLatitude(), event.getLongitude()));
			}
		}
    	
    	// get geodata from flickr
		try {
			System.out.println("start flickr search");
			// get photo search xml
	        URLConnection uc = new URL("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=" + _flickr_api_key + "&per_page=" + _flickr_photosAmount + "&has_geo=&extras=geo&woe_id=2345496&place_id=xI0a3VebApgsO5bO").openConnection();
	        DataInputStream dis = new DataInputStream(uc.getInputStream());
	        String nextline;
	        // go through each line
	        int i=0;
	        while ((nextline = dis.readLine()) != null) {
	            if(nextline.indexOf("photo id") != -1) {
	            	System.out.println(i + "of flickr photo " + _flickr_photosAmount);
	            	i++;
	            	XMLElement xml = new XMLElement();
	                xml.parseString(nextline);
	                Enumeration enumm = xml.enumerateAttributeNames();
	                GeoPosition position = new GeoPosition(0,0);
	                while (enumm.hasMoreElements()) {
	                    String key = (String) enumm.nextElement();
	                    String value = xml.getStringAttribute(key);
	                    // extract latitude and logitude
	                    if(key.equals("LATITUDE"))
	                    	position.latitude = Float.parseFloat(value);
	                    if(key.equals("LONGITUDE"))
	                    	position.longitude = Float.parseFloat(value);
	                }
	                _flickr_positions.add(position);
	                System.out.println(position.latitude + " " + position.longitude);
	            }
	        }
	        dis.close();
	        System.out.println("search finished");
		} catch (MalformedURLException me) {
            System.out.println("MalformedURLException: " + me);
        } catch (IOException ioe) {
            System.out.println("IOException: " + ioe);
        }
		
        // panoramio
        _panoramio_positions = r.get(new GeoPosition(13.4f, 52.5f), .2f, "upload_date", "full", "thumbnail");
        System.out.println(_panoramio_positions.size());
        for(GeoPosition pos:_panoramio_positions)
        	System.out.println("panoramio " + pos.latitude + " " + pos.longitude);
        
        // get twitter data
        
        String geolocationBerlin = latitudeOffset + "%2C" + longitudeOffset  + "%2C";
    	String searchQuery = "http://search.twitter.com/search.json?geocode=" + geolocationBerlin + "150km&rpp=100";
        
        // load twitter json string
    	System.out.println("getting twitter data..");
    	String[] responseStrings = CCIOUtil.loadStrings(searchQuery);
		
		// extract content
		String jsonData = responseStrings[0];
		jsonData = jsonData.substring(jsonData.indexOf("["), jsonData.lastIndexOf("]")+1);

		// parse json
		_twitterData  = null;
		try
		{
			_twitterData = new JSONArray(jsonData);
		}
		catch (JSONException e)
		{
			System.out.println(e.toString());
		}
		
		// get tweets location
		try
		{
			for(int i = 0; i < _twitterData.length(); i++) {
				JSONObject incomObject = _twitterData.getJSONObject(i);
				String location = incomObject.getString("location");
				String text = incomObject.getString("text");
				// extract tweets with lat and lon , this is hardcoded for berlin..
				if(location.indexOf("52.") != -1) {
					String[] extractedLocation = location.substring(location.indexOf("52."), location.length()).split(",");
					float latitude = Float.parseFloat(extractedLocation[0]);
					float longitude = Float.parseFloat(extractedLocation[1]);
					System.out.println("twitter " + latitude + "," + longitude + "	text: " + text);
					_twitter_positions.add(new GeoPosition(latitude, longitude));
				}
			}
		}
		catch(JSONException e)
		{
			System.out.println(e.toString());
		}
        
        // there is no place like homeplace
        
        // fhp
        _home_positions.add(new GeoPosition(52.41192233525607f, 13.041715621948242f));
        // sodke street
        _home_positions.add(new GeoPosition(52.5457533f, 13.4326409f));
        // alexanderplatz
        _home_positions.add(new GeoPosition(52.5225977f, 13.4148965f));
        
        // Adding the users position via WhoisRequest
        WhoisRequest wr = new WhoisRequest();
        
// 		Add service to find the ip of the client
        _home_positions.add(wr.get("77.188.18.191"));
        
    	/*
    	 *  build visualization
    	 */
        fpscounter(true);
        framerate(UNDEFINED);

        camera().plugins().add(new ArcBall());
        camera().position().z = 730;

        
        // lastfm
        int meshWidth = _lastfm_positions.size();
        int meshHeight = 1;

        _lastfm_mesh = JoglLEDDisplay.create(meshWidth, meshHeight,
                                              bin(BIN_FRAME_SETUP),
                                              Bitmaps.getBitmap(Resource.getStream("demo/common/particle-round.png")),
                                              true);
//        _myLEDDisplay.addMask(Bitmaps.getBitmap(Resource.getStream("demo/common/mask256x128.png")));
        bin(BIN_3D).add(_lastfm_mesh);
        
        _lastfm_mesh.backgroundcolor().set(1f);
        _lastfm_mesh.scale().set(8, 8);
        _lastfm_mesh.getPointSpriteMaterialPlugin().minpointsize = .1f;
        _lastfm_mesh.getPointSpriteMaterialPlugin().maxpointsize = 64;
        _lastfm_mesh.getPointSpriteMaterialPlugin().pointsize = 17;
        
        // set koords here
        for (int i = 0; i < _lastfm_mesh.points().size(); i++) {
            final Vector3f v = _lastfm_mesh.points().get(i);
            int x = i % meshWidth;
            int y = i / meshWidth;
            v.y = (_lastfm_positions.get(i).latitude - latitudeOffset) * magnify;
            v.x = (_lastfm_positions.get(i).longitude - longitudeOffset) * magnify;
        }
        
        
        // flickr
        meshWidth = _flickr_positions.size();
        meshHeight = 1;

        _flickr_mesh = JoglLEDDisplay.create(meshWidth, meshHeight,
                                              bin(BIN_FRAME_SETUP),
                                              Bitmaps.getBitmap(Resource.getStream("demo/common/particle-round.png")),
                                              true);
//        _myLEDDisplay.addMask(Bitmaps.getBitmap(Resource.getStream("demo/common/mask256x128.png")));
        bin(BIN_3D).add(_flickr_mesh);

        _flickr_mesh.backgroundcolor().set(1f, 1f, .25f);
        _flickr_mesh.scale().set(8, 8);
        _flickr_mesh.getPointSpriteMaterialPlugin().minpointsize = .1f;
        _flickr_mesh.getPointSpriteMaterialPlugin().maxpointsize = 64;
        _flickr_mesh.getPointSpriteMaterialPlugin().pointsize = 20;
        
        // set koords here
        for (int i = 0; i < _flickr_mesh.points().size(); i++) {
            final Vector3f v = _flickr_mesh.points().get(i);
            int x = i % meshWidth;
            int y = i / meshWidth;
            v.y = (_flickr_positions.get(i).latitude - latitudeOffset) * magnify;
//            v.z = 100;
            v.x = (_flickr_positions.get(i).longitude - longitudeOffset) * magnify;
        }
        
        // panoramio
        meshWidth = _panoramio_positions.size();
        meshHeight = 1;

        _panoramio_mesh = JoglLEDDisplay.create(meshWidth, meshHeight,
                                              bin(BIN_FRAME_SETUP),
                                              Bitmaps.getBitmap(Resource.getStream("demo/common/particle-round.png")),
                                              true);
//        _myLEDDisplay.addMask(Bitmaps.getBitmap(Resource.getStream("demo/common/mask256x128.png")));
        bin(BIN_3D).add(_panoramio_mesh);

        _panoramio_mesh.backgroundcolor().set(.9f, .14f, 0f);
        _panoramio_mesh.scale().set(8, 8);
        _panoramio_mesh.getPointSpriteMaterialPlugin().minpointsize = .1f;
        _panoramio_mesh.getPointSpriteMaterialPlugin().maxpointsize = 64;
        _panoramio_mesh.getPointSpriteMaterialPlugin().pointsize = 24;
        
        // set koords here
        for (int i = 0; i < _panoramio_mesh.points().size(); i++) {
            final Vector3f v = _panoramio_mesh.points().get(i);
            int x = i % meshWidth;
            int y = i / meshWidth;
            v.y = (_panoramio_positions.get(i).latitude - latitudeOffset) * magnify;
//            v.z = 100;
            v.x = (_panoramio_positions.get(i).longitude - longitudeOffset) * magnify;
        }
        
     // twitter
        meshWidth = _twitter_positions.size();
        meshHeight = 1;

        _twitter_mesh = JoglLEDDisplay.create(meshWidth, meshHeight,
                                              bin(BIN_FRAME_SETUP),
                                              Bitmaps.getBitmap(Resource.getStream("demo/common/particle-round.png")),
                                              true);
//        _myLEDDisplay.addMask(Bitmaps.getBitmap(Resource.getStream("demo/common/mask256x128.png")));
        bin(BIN_3D).add(_twitter_mesh);
        
        _twitter_mesh.backgroundcolor().set(.8f, .8f, 1f);
        _twitter_mesh.scale().set(8, 8);
        _twitter_mesh.getPointSpriteMaterialPlugin().minpointsize = .1f;
        _twitter_mesh.getPointSpriteMaterialPlugin().maxpointsize = 64;
        _twitter_mesh.getPointSpriteMaterialPlugin().pointsize = 17;
        
        // set koords here
        for (int i = 0; i < _twitter_mesh.points().size(); i++) {
            final Vector3f v = _twitter_mesh.points().get(i);
            int x = i % meshWidth;
            int y = i / meshWidth;
            v.y = (_twitter_positions.get(i).latitude - latitudeOffset) * magnify;
            v.x = (_twitter_positions.get(i).longitude - longitudeOffset) * magnify;
        }
        
        
        // home
        meshWidth = _home_positions.size();
        meshHeight = 1;

        _home_mesh = JoglLEDDisplay.create(meshWidth, meshHeight,
                                              bin(BIN_FRAME_SETUP),
                                              Bitmaps.getBitmap(Resource.getStream("demo/common/particle-round.png")),
                                              true);
//        _myLEDDisplay.addMask(Bitmaps.getBitmap(Resource.getStream("demo/common/mask256x128.png")));
        bin(BIN_3D).add(_home_mesh);

        _home_mesh.backgroundcolor().set(1f, 1f, .85f);
        _home_mesh.scale().set(8, 8);
        _home_mesh.getPointSpriteMaterialPlugin().minpointsize = .1f;
        _home_mesh.getPointSpriteMaterialPlugin().maxpointsize = 64;
        _home_mesh.getPointSpriteMaterialPlugin().pointsize = 57;
        
        // set koords here
        for (int i = 0; i < _home_mesh.points().size(); i++) {
            final Vector3f v = _home_mesh.points().get(i);
            int x = i % meshWidth;
            int y = i / meshWidth;
            v.y = (_home_positions.get(i).latitude - latitudeOffset) * magnify;
//            v.z = 100;
            v.x = (_home_positions.get(i).longitude - longitudeOffset) * magnify;
        }
    }

    public void loop(final float theDeltaTime) {
        CameraMover.handleKeyEvent(_lastfm_mesh.camera(),
                                   event(),
                                   theDeltaTime);

        /* pulse background color */
        _myCounter += theDeltaTime;
        // final float myColor = (float)Math.abs(Math.sin(_myCounter * 0.5f)) * 0.9f + 0.1f;
        // _myLEDDisplay.backgroundcolor().set(myColor);
    }

    public DisplayCapabilities createDisplayCapabilities() {
        DisplayCapabilities myDisplayCapabilities = new DisplayCapabilities();
        myDisplayCapabilities.backgroundcolor.set(0f);
        myDisplayCapabilities.width = 1280;
        myDisplayCapabilities.height = 750;
        myDisplayCapabilities.antialiasinglevel = 4;
//        myDisplayCapabilities.undecorated = true;
        return myDisplayCapabilities;
    }
    
    public static void main(String[] args) {
        G.init(GeoDataVisualization.class);
    }
}
